<?php

class Player {
  /** @var integer */
  public $id;
  /** @var integer */
  public $tableId;
  /** @var integer */
  public $gameId;
  /** @var integer */
  public $userId;
  /** @var sring */
  public $status;
  /** @var boolean */
  public $isBelotBot;
  /** @var Cards array */
  public $playerDeck;
  /** @var Combination array */
  public $plyersCombinations;
    /** @var boolean */
  public $isDealer;
  /** @var integer */
  public $points;
  
  const STATUS_NEW     = 'new';
  const STATUS_PLAYING = 'playing';
  const STATUS_WINNER  = 'winner';
  const STATUS_LOSER   = 'loser';
  
  public static $STATUS_TITLES = array(
    self::STATUS_NEW     => 'New',
    self::STATUS_PLAYING => 'Playing',
    self::STATUS_WINNER  => 'Winner',
    self::STATUS_LOSER   => 'Loser',
  );
  
    /**
   * @var Array<Player> - array of cached Player objects used when there
   *              is a need to repeatedly load the same objects from database.
   */
  private static $CACHED_GAME_PLAYERS = array();
  private static $CACHED_GAME_PLAYERS_BY_ID = array();

/**
   * Loads a Player object from database or creates a new Player instance if no $id
   * paramenter given.
   * @param integer $gameId
   * @param integer $userId
   */
  public function __construct($gameId = null, $userId = null)
  {
    $this->Init();
    if (!ValidId($gameId) || !ValidId($userId) || !$this->Load($gameId, $userId))
      $this->Init();
  }

  /**
   * sets default values to class's properties.
   */
  private function Init()
  {
    $this->id = -1;
    $this->tableId = -1;
    $this->gameId = -1;
    $this->userId = -1;
    $this->isBelotBot = false;
    $this->isDealer = false;
    $this->status = Player::STATUS_NEW;
  }
  
  /**
   * Loads Player from database
   * @param integer $gameId - Game id
   * @param integer $userId - User id
   */
  private function Load($gameId, $userId)
  {
    if (!$this->LoadData($gameId, $userId))
      return false;
    return true;
  }

   /**
   * Loads a Player from database
   * @param integer $gameId - Game id
   * @param integer $userId - User id
   * @return boolean true if object was loaded
   */
  private function LoadData($gameId, $userId)
  {
    if (!ValidId($gameId) || !ValidId($userId))
      return false;
    
    $query = "SELECT ALL gp.*"
             . " FROM game_players AS gp"
             . " WHERE gp.game_id=" . ToSqlQuotedString($gameId)
              . " AND gp.user_id=" . ToSqlQuotedString($userId);
    $rows = ExecuteQuery($query);
    // return false if nothing loaded
    if (count($rows) != 1)
      return false;
    $this->SetPropertyValues($rows[0]);
    return true;
  }


  /**
   * Populates basic model properties with data extracted from database.
   * @param array $data - dictionary of (<table column name> => <value>)
   * @param array $properties - column->property mapping for the additional properties to add to the model.
   */
  private function SetPropertyValues(&$data, $properties)
  {
    $this->id = $data['id'];
    $this->tableId = $data['table_id'];
    $this->gameId = $data['game_id'];
    $this->userId = $data['user_id'];
   
    $this->startWeighInId = $data['start_weigh_in_id'];
    $this->finalWeighInId = $data['final_weigh_in_id'];
    $this->currentWeighInId = $data['current_weigh_in_id'];
    $this->inGameOfficialWeighInId = $data['in_game_official_weigh_in_id'];


    $this->status = $data['status'];
    
    // set dynamic properties
    SetDynamicPropertiesOnModel($this, $properties, $data);
  }
  
  public function Save()
  {
    $values = array();
    
    $values['category_id'] = intval($this->categoryId);
    $values['name'] = $this->name;
    $values['title'] = $this->title;
    $values['image_id'] = $this->imageId;
    $values['views'] = $this->views;
    $values['rating'] = $this->rating;
    $values['rating_count'] = $this->ratingCount;
    $values['status'] = $this->status;
    $values['width'] = intval($this->width); // not null
    $values['height'] = $this->height;
 
    
    
    $oldGame = new Game($this->id);
    if ($oldGame->id && $oldGame->id > 0)
    {
      $res = DB::table('games')
              ->where('id', '=', $oldGame->id)
              ->update($values);
    }
    else
      $res = DB::table('games')->insert($values);

  }
  
  public function Delete()
  {

  }
  
  public static function GetLastGameId()
  {
    return DB::table('games')->max('id');
  }
  
  
  /* -------- PLAYERS CACHE BEGIN -------- */
  /**
   * Loads game players to cache
   * @param Array $gameId - gamr for which to load players
   * @param Array $userIds - specific user ids to load
   * @param Array $playerIds - specific player ids to load
   */
  public static function LoadPlayersToCache($gameId = null, $userIds = null, $playerIds = null)
  {
    if (ValidId($gameId) && count($userIds) > 0)
    {
      $where = 'gp.game_id=' . ToSqlQuotedString($gameId)
              . ' AND ' . BuildSqlInClause('gp.user_id', $userIds);
      Player::AddPlayersToCache(Player::LoadPlayers($where));
    }
    else if (is_array($playerIds) && count($playerIds) > 0)
    {
      $uncachedPlayerIds = array();
      foreach ($playerIds as $playerId)
        if (ValidId($playerId) && !Player::PlayerIsCached($playerId))
          $uncachedPlayerIds[] = $playerId;
      
      // group players in chunks so that the server is not overloaded
      $groupedPlayerIds = GroupModelIdsInChunks($uncachedPlayerIds);
      // load players in chunks
      foreach ($groupedPlayerIds as $ids)
        Player::AddPlayersToCache(Player::LoadPlayers(BuildSqlInClause('gp.id', $ids)));
    }
    else
      return;
  }

  /**
   * @param Array<Player> $gamePlayers
   */
  public static function AddPlayersToCache($gamePlayers)
  {
    foreach ($gamePlayers as $player)
    {
      if (ValidId($player->id))
      {
        @Player::$CACHED_GAME_PLAYERS[$player->gameId][$player->userId] = $player;
        @Player::$CACHED_GAME_PLAYERS_BY_ID[$player->id] = $player;
      }
    }
  }

  /**
   * Checks that the game player exists in cache.
   * @param Integer $playerId
   */
  public static function PlayerIsCached($playerId)
  {
    return ValidId($playerId) && @array_key_exists($playerId, Player::$CACHED_GAME_PLAYERS_BY_ID) && Player::$CACHED_GAME_PLAYERS_BY_ID[$playerId];
  }
  
  /**
   * Checks that the game player exists in cache.
   * @param Integer $playerId
   */
  public static function PlayerIsCachedByUserId($gameId, $userId)
  {
    return ValidId($gameId) && ValidId($userId) && @array_key_exists($gameId, Player::$CACHED_GAME_PLAYERS)
          && @array_key_exists($userId, Player::$CACHED_GAME_PLAYERS[$gameId])
          && @Player::$CACHED_GAME_PLAYERS[$gameId][$userId];
  }
  
  /**
   * Loads Player object from cache, or populates the cache with all the players
   *          for a certain game.
   * @param Integer $playerId
   */
  public static function LoadCachedPlayerById($playerId)
  {
    if (!ValidId($playerId))
      return new Player();
    
    if (!@array_key_exists($playerId, Player::$CACHED_GAME_PLAYERS_BY_ID))
    {
      $gamePlayer = Player::LoadById($playerId);
      if (ValidId($gamePlayer->id))
        Player::AddPlayersToCache(array($gamePlayer));
    }
    
    $gamePlayer = @Player::$CACHED_GAME_PLAYERS_BY_ID[$playerId];
    if (!ValidId($gamePlayer->id))
      $gamePlayer = new Player();
    return $gamePlayer;
  }
  
  
  
}

?>

?>
